package com.mf.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mf.dto.PriceCalculateParams;
import com.mf.entity.Positions;
import com.mf.entity.SellingHistory;
import com.mf.entity.Transactions;
import com.mf.entity.User;
import com.mf.entity.code.*;
import com.mf.exception.CustomExceptionHandler;
import com.mf.mapper.PositionsMapper;
import com.mf.mapper.SellingHistoryMapper;
import com.mf.mapper.TransactionsMapper;
import com.mf.mapper.UserMapper;
import com.mf.mapper.code.*;
import com.mf.service.ITransactionsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mf.service.IWorkdayService;
import com.mf.ulits.SelectCodeService;
import com.mf.vo.transactions.TransactionsListVo;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 交易表 服务实现类
 * </p>
 *
 * @author mf
 * @since 2024-05-16
 */
@Service
public class TransactionsServiceImpl extends ServiceImpl<TransactionsMapper, Transactions> implements ITransactionsService {
    @Resource
    private Code000Mapper code000Mapper;

    @Resource
    private Code001Mapper code001Mapper;

    @Resource
    private Code002AMapper code002AMapper;

    @Resource
    private Code002BMapper code002BMapper;
    @Resource
    private Code003Mapper code003Mapper;
    @Resource
    private Code300AMapper code300AMapper;
    @Resource
    private Code300BMapper code300BMapper;
    @Resource
    private Code301Mapper code301Mapper;
    @Resource
    private Code600AMapper code600AMapper;
    @Resource
    private Code600BMapper code600BMapper;
    @Resource
    private Code601Mapper code601Mapper;
    @Resource
    private Code603Mapper code603Mapper;
    @Resource
    private Code605Mapper code605Mapper;
    @Resource
    private TransactionsMapper transactionsMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private PositionsMapper positionsMapper;

    @Resource
    private IWorkdayService workdayService;
    @Resource
    private SellingHistoryMapper sellingHistoryMapper;


    /**
     * 批量添加交易记录
     */
    @Override
    public Void addTransactionsList(TransactionsListVo transactionsVo) {
        PriceCalculateParams priceCalculateParams = new PriceCalculateParams();
        for (String dm : transactionsVo.getDm()) {
            Transactions transactions = new Transactions();
            System.out.println(dm);
            if (dm.startsWith("600")) {
                if (Integer.parseInt(dm) < 600500) {
                    final LambdaQueryWrapper<Code600A> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(Code600A::getDm, dm)
                            .eq(Code600A::getD, transactionsVo.getDate());
                    Code600A code = code600AMapper.selectOne(queryWrapper);
                    priceCalculateParams = findPriceCalculateParams(code.getO());
                } else  {
                    final LambdaQueryWrapper<Code600B> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(Code600B::getDm, dm)
                            .eq(Code600B::getD, transactionsVo.getDate());
                    Code600B code = code600BMapper.selectOne(queryWrapper);
                    priceCalculateParams = findPriceCalculateParams(code.getO());
                }
            }else if(dm.startsWith("000")){
                final LambdaQueryWrapper<Code000> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Code000::getDm, dm)
                        .eq(Code000::getD, transactionsVo.getDate());
                Code000 code = code000Mapper.selectOne(queryWrapper);
                priceCalculateParams = findPriceCalculateParams(code.getO());
            }else if(dm.startsWith("001")){
                final LambdaQueryWrapper<Code001> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Code001::getDm, dm)
                        .eq(Code001::getD, transactionsVo.getDate());
                Code001 code = code001Mapper.selectOne(queryWrapper);
                priceCalculateParams = findPriceCalculateParams(code.getO());
            }else if(dm.startsWith("002")){
                if (Integer.parseInt(dm) < 2500) {
                    final LambdaQueryWrapper<Code002A> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(Code002A::getDm, dm)
                            .eq(Code002A::getD, transactionsVo.getDate());
                    Code002A code = code002AMapper.selectOne(queryWrapper);
                    priceCalculateParams = findPriceCalculateParams(code.getO());
                } else  {
                    final LambdaQueryWrapper<Code002B> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(Code002B::getDm, dm)
                            .eq(Code002B::getD, transactionsVo.getDate());
                    Code002B code = code002BMapper.selectOne(queryWrapper);
                    priceCalculateParams = findPriceCalculateParams(code.getO());
                }
            }else if(dm.startsWith("003")){
                final LambdaQueryWrapper<Code003> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Code003::getDm, dm)
                        .eq(Code003::getD, transactionsVo.getDate());
                Code003 code = code003Mapper.selectOne(queryWrapper);
                priceCalculateParams = findPriceCalculateParams(code.getO());
            }else if(dm.startsWith("300")){
                if (Integer.parseInt(dm) < 300500) {
                    final LambdaQueryWrapper<Code300A> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(Code300A::getDm, dm)
                            .eq(Code300A::getD, transactionsVo.getDate());
                    Code300A code = code300AMapper.selectOne(queryWrapper);
                    priceCalculateParams = findPriceCalculateParams(code.getO());
                } else  {
                    final LambdaQueryWrapper<Code300B> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(Code300B::getDm, dm)
                            .eq(Code300B::getD, transactionsVo.getDate());
                    Code300B code = code300BMapper.selectOne(queryWrapper);
                    priceCalculateParams = findPriceCalculateParams(code.getO());
                }
            }else if(dm.startsWith("301")){
                final LambdaQueryWrapper<Code301> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Code301::getDm, dm)
                        .eq(Code301::getD, transactionsVo.getDate());
                Code301 code = code301Mapper.selectOne(queryWrapper);
                priceCalculateParams = findPriceCalculateParams(code.getO());
            }else if(dm.startsWith("601")){
                final LambdaQueryWrapper<Code601> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Code601::getDm, dm)
                        .eq(Code601::getD, transactionsVo.getDate());
                Code601 code = code601Mapper.selectOne(queryWrapper);
                priceCalculateParams = findPriceCalculateParams(code.getO());
            }else if(dm.startsWith("603")){
                final LambdaQueryWrapper<Code603> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Code603::getDm, dm)
                        .eq(Code603::getD, transactionsVo.getDate());
                Code603 code = code603Mapper.selectOne(queryWrapper);
                priceCalculateParams = findPriceCalculateParams(code.getO());
            }else if(dm.startsWith("605")){
                final LambdaQueryWrapper<Code605> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Code605::getDm, dm)
                        .eq(Code605::getD, transactionsVo.getDate());
                Code605 code = code605Mapper.selectOne(queryWrapper);
                priceCalculateParams = findPriceCalculateParams(code.getO());
            }
            transactions.setDm(dm);
            transactions.setType2("buy");
            transactions.setDate(transactionsVo.getDate());
            transactions.setType(transactionsVo.getType());
            transactions.setUserId(transactionsVo.getUserId());
            transactions.setPrice(priceCalculateParams.getPrice());
            transactions.setAmount(priceCalculateParams.getAmount());
            transactions.setQuantity(priceCalculateParams.getQuantity());
            transactions.setCost(priceCalculateParams.getCost());
            addTransactions(transactions);
        }
        return null;
    }
    /**
     * 根据金额查询其他参数
     */
    public PriceCalculateParams findPriceCalculateParams(BigDecimal price) {
        final BigDecimal quantity = getBigDecimal(price);

        // 数量 * 价格 获取最终的金额
        BigDecimal finalAmount = quantity.multiply(price);
        final PriceCalculateParams priceCalculateParams = new PriceCalculateParams();

        priceCalculateParams.setQuantity(quantity.intValue());
        priceCalculateParams.setAmount(finalAmount);
        priceCalculateParams.setPrice(price);
        // 交易费用等于金额 的万分之五 保留2位小数
        priceCalculateParams.setCost(finalAmount.multiply(new BigDecimal("0.0005")).setScale(2, RoundingMode.HALF_UP));
        return priceCalculateParams;
    }

    /**
     * 获取数量
     * @param price 价格
     * @return 数量
     */
    private static BigDecimal getBigDecimal(BigDecimal price) {
        BigDecimal defaultAmount = new BigDecimal(10000);

        // 进行除法运算
        BigDecimal divisionResult = defaultAmount.divide(price, 10, RoundingMode.HALF_UP); // 使用足够高的精度来避免丢失数据

        // 保留到百位，即设置精度为2，并四舍五入
        BigDecimal roundedToHundreds = divisionResult.setScale(2, RoundingMode.HALF_UP);

        // 如果需要保留到百位的整数部分，即截断小数部分
        BigDecimal truncatedToHundreds = roundedToHundreds.setScale(0, RoundingMode.DOWN);

        return truncatedToHundreds.divide(new BigDecimal("100"), 0, RoundingMode.UP).multiply(new BigDecimal("100"));
    }


    /**
     * 新增交易记录
     */
    @Override
    public void addTransactions(Transactions transactions) {
        User user = userMapper.selectById(transactions.getUserId());

        if (user == null) {
            throw new CustomExceptionHandler("用户不存在");
        }

        // 获取持仓表数据
        LambdaQueryWrapper<Positions> positionsQueryWrapper = new LambdaQueryWrapper<>();
        positionsQueryWrapper.eq(Positions::getUserId, transactions.getUserId());
        positionsQueryWrapper.eq(Positions::getDm, transactions.getDm());
        Positions serviceOne = positionsMapper.selectOne(positionsQueryWrapper);
        if("buy".equals(transactions.getType2())){
            if (null != serviceOne) {
//                throw new CustomExceptionHandler("该股票已持仓,不可在买入");
                System.out.println(serviceOne.getDm()+"股票已买入");
                return;
                // 如果有持仓更新数量和金额
//                    serviceOne.setQuantity(serviceOne.getQuantity() + transactions.getQuantity());
//                    serviceOne.setAmount(serviceOne.getAmount().add(transactions.getAmount()));
//                    positionsMapper.update(serviceOne, positionsQueryWrapper);
            }
        }

        int save = transactionsMapper.insert(transactions);
        if (save > 0) {
            // 实时更新用户金额"buy".
            if ("buy".equals(transactions.getType2())) {
                // 买入
                user.setMoney(user.getMoney().subtract(transactions.getAmount()).subtract(transactions.getCost()));
                // 新增持仓数据
                Positions positions = new Positions();
                positions.setPrice(transactions.getPrice());
                positions.setAmount(transactions.getAmount());
                positions.setDate(transactions.getDate());
                positions.setDm(transactions.getDm());
                positions.setQuantity(transactions.getQuantity());
                positions.setUserId(transactions.getUserId());
                positionsMapper.insert(positions);
            } else {

                if (user.getMoney().subtract(transactions.getAmount()).compareTo(BigDecimal.ZERO) < 0) {
                    throw new CustomExceptionHandler("余额不足");
                }
                // 卖出
                user.setMoney(user.getMoney().add(transactions.getAmount()).subtract(transactions.getCost()));

                // 更新持仓表数据
                // 卖出数量等于持仓数量直接删除数据
                if (transactions.getQuantity() == serviceOne.getQuantity()) {
                    // 设置卖出历史数据
                    setSellingHistory(transactions, serviceOne);

                    positionsMapper.delete(positionsQueryWrapper);
                } else {
                    // 否则更新数量
                    serviceOne.setQuantity(serviceOne.getQuantity() - transactions.getQuantity());
                    positionsMapper.update(serviceOne, positionsQueryWrapper);
                }


            }
            // 更新用户金额
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getId, user.getId());
            userMapper.update(user, queryWrapper);
        }
    }

    private void setSellingHistory(Transactions transactions, Positions serviceOne) {
        // 获取最近的日期为开始日期
        LambdaQueryWrapper<Transactions> transactionsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        transactionsLambdaQueryWrapper.eq(Transactions::getUserId, transactions.getUserId())
                .eq(Transactions::getDm, transactions.getDm());
        transactionsLambdaQueryWrapper.orderByDesc(Transactions::getDate);
        Transactions transactionsList =
                transactionsMapper.selectList(transactionsLambdaQueryWrapper).get(1);

        // 将持仓数据更新到买入历史表中
        SellingHistory sellingHistory = new SellingHistory();
        sellingHistory.setUserId(serviceOne.getUserId());
        sellingHistory.setBuyDate(serviceOne.getDate());
        sellingHistory.setBuyMoney(serviceOne.getAmount());
        sellingHistory.setSaleDate(transactions.getDate());
        sellingHistory.setSaleMoney(transactions.getAmount());
        sellingHistory.setCost(transactions.getCost().add(transactionsList.getCost()));
        sellingHistory.setHoldingDays(workdayService.findWorkDayByScopeSum(transactionsList.getDate(),
                transactions.getDate()));
        sellingHistory.setDm(transactions.getDm());
        sellingHistory.setStatus(transactions.getAmount().compareTo(serviceOne.getAmount()) > 0 ? 1 : 0);
        sellingHistoryMapper.insert(sellingHistory);
    }

    /**
     * 待出售的股票
     */
    @Override
    public List<Transactions> findAwaitSaleByUserId(Integer userId) {
        LambdaQueryWrapper<Transactions> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Transactions::getUserId, userId);
        List<Transactions> transactionsList = transactionsMapper.selectList(queryWrapper);
        // 已买入的股票
        List<Transactions> transactionsByBuy = new ArrayList<>();
        return null;
    }
}
